﻿using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Collections.Generic;
using System.Web.UI.HtmlControls;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.IO;

namespace Webcoda.SP.WP {

    [Guid("012DE6D3-1A01-45ec-9C12-F546F97B6856")]
    public class Twitter : System.Web.UI.WebControls.WebParts.WebPart // , ICallbackEventHandler  // ****** REMOVE CALLBACK **********
    {

        // Page UI
        private Panel uiPnlMainContainer = new Panel();
        private Repeater uiRptDisplay = new Repeater();
        private TextBox uiTxtMessage = new TextBox();
        private Button uiBtnUpdate = new Button();
        private HyperLink uiHypLnkMore = new HyperLink();
        private Panel uiPnlDisplayContainer = new Panel();
        private Panel uiPnlUpdateContainer = new Panel();
        private Panel uiPnlMoreContainer = new Panel();

        // Global Variables
        private SPWeb _WebContext = SPContext.Current.Web;
        private SPSite _SiteContext = SPContext.Current.Site;
        private SPList _MainList;

        private StringBuilder _ErrorMessageLog = new StringBuilder();
        private string _EventArgument = string.Empty;
        private const string LISTNAMEDEFUALT = "Twitter List";
        private const string LISTQUERYDEFAULT = "<OrderBy><FieldRef Name=\"Created\" Ascending=\"FALSE\"/></OrderBy>";

        #region Properties

        private string _ListName = LISTNAMEDEFUALT;
        [Category("Configuration")]
        [WebBrowsable(true)]
        [WebDescription("Please enter Twitter list name")]
        [WebDisplayName("List Name")]
        [Personalizable(PersonalizationScope.User)]
        public string ListName {
            get {
                // Check list name
                if (string.IsNullOrEmpty(this._ListName)) {
                    this._ListName = LISTNAMEDEFUALT;
                }
                return this._ListName;
            }
            set {
                // Check Value
                if (string.IsNullOrEmpty(value)) {
                    value = LISTNAMEDEFUALT;
                }
                this._ListName = value;
            }
        }
        
        private string _ListQuery = LISTQUERYDEFAULT;
        [Category("Configuration")]
        [WebBrowsable(true)]
        [WebDescription("Please enter Collaborative Application Markup Language (CAML) Query.")]
        [WebDisplayName("CAML Query")]
        [Personalizable(PersonalizationScope.User)]
        public string ListQuery {
            get {
                // Check list query
                if (string.IsNullOrEmpty(this._ListQuery)) {
                    this._ListQuery = LISTQUERYDEFAULT;
                }
                return this._ListQuery;
            }
            set {
                // Check value
                if (string.IsNullOrEmpty(value)) {
                    value = LISTQUERYDEFAULT;
                }
                this._ListQuery = value;
            }
        }

        private uint _ListRowLimit = 5;
        [Category("Configuration")]
        [WebBrowsable(true)]
        [WebDescription("Please enter number of items to display")]
        [WebDisplayName("Number of items to display")]
        [Personalizable(PersonalizationScope.User)]
        public uint ListRowLimit {
            get {
                return this._ListRowLimit;
            }
            set {
                this._ListRowLimit = value;
            }
        }

        private int _MessageLimit = 140;
        [Category("Configuration")]
        [WebBrowsable(true)]
        [WebDescription("Please enter message number of characters")]
        [WebDisplayName("Message max characters")]
        [Personalizable(PersonalizationScope.User)]
        public int MessageLimit {
            get {
                return this._MessageLimit;
            }
            set {
                this._MessageLimit = value;
            }
        }

        private int _ListTotalItems = 30;
        [Category("Configuration")]
        [WebBrowsable(true)]
        [WebDescription("Please enter total number of items in list")]
        [WebDisplayName("Total Number of items in list")]
        [Personalizable(PersonalizationScope.User)]
        public int ListTotalItems {
            get {
                return this._ListTotalItems;
            }
            set {
                this._ListTotalItems = value;
            }
        }

        #endregion

        #region Webpart Methods

        public Twitter() {
            ExportMode = WebPartExportMode.All;
        }
        
        /// <summary>
        /// Create Controls
        /// </summary>
        protected override void CreateChildControls() {
            try {
                // Need this to validate post parameters
                //this._WebContext.AllowUnsafeUpdates = true;
                //this._WebContext.ValidateFormDigest();

                // Load Controls
                this.LoadControls();

                //Register Scripts
                this.RegisterScripts();

                // Databind controls
                this.DatabindControls();  
 
                // Set webpart setting
                this.SetWebpartSetting();

                // Create Controls
                base.CreateChildControls();               
            } catch (Exception ex) {
                this._ErrorMessageLog.AppendLine(ex.Message);
            }
        }       

        /// <summary>
        /// Render overwrite the controls on the page
        /// </summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer) {
            try {
                if (this._ErrorMessageLog.Length > 0) {
                    DisplayErrorMessage(writer);
                    return;
                }

                // Display Container                
                uiPnlMainContainer.RenderControl(writer);

            } catch (Exception ex) {
                this._ErrorMessageLog.AppendLine(ex.Message);
                DisplayErrorMessage(writer);
            }
        }


        /// <summary>
        /// Returns the results of a callback event that targets a control.  // ****** REMOVE CALLBACK **********
        /// </summary>
        /// <param name="eventArgument"></param>
        //public void RaiseCallbackEvent(string eventArgument) {
        //    // Processes a callback event on the server using the event
        //    // argument from the client.
        //    this._EventArgument = eventArgument;
        //}

        /// <summary>
        /// This is the call back functions that returns the results to the client // ****** REMOVE CALLBACK **********
        /// </summary>
        /// <returns></returns>
        //public string GetCallbackResult() {
        //    // Write the Output to Client
        //    StringWriter sWriter = new StringWriter();
        //    HtmlTextWriter writer = new HtmlTextWriter(sWriter);

        //    // Returns the results of a callback event to the client.
        //    if (!string.IsNullOrEmpty(this._EventArgument)) {

        //        try {
        //            // Load Controls
        //            this.LoadControls();

        //        } catch (Exception ex) {
        //            this._ErrorMessageLog.AppendLine(ex.Message);
        //        }

        //        // Set the Text box 
        //        this.uiTxtMessage.Text = this._EventArgument;

        //        // Call the Click event
        //        this.uiBtnUpdate_Click(null, null);

        //        // Return the Result
        //        if (string.IsNullOrEmpty(this._ErrorMessageLog.ToString())) {
        //            // Success
        //            uiPnlDisplayContainer.RenderControl(writer);
        //        } else {
        //            // Error 
        //            DisplayErrorMessage(writer);
        //        }
        //    }

        //    this._EventArgument = string.Empty;
        //    return sWriter.ToString();

        //}
        #endregion

        #region Private Methods

        /// <summary>
        /// Webpart settings
        /// </summary>
        private void SetWebpartSetting() {
            // Set the title URL
            this.TitleUrl = this.uiHypLnkMore.NavigateUrl;
        }

        /// <summary>
        /// Register Scripts
        /// </summary>
        private void RegisterScripts() {
            ClientScriptManager pageScriptManager = this.Page.ClientScript;

            // Register Support Scrips  
            if (!pageScriptManager.IsClientScriptIncludeRegistered("webcoda.support.js")) {
                pageScriptManager.RegisterClientScriptInclude(this.GetType(), "webcoda.support.js", "/_layouts/webcoda.twitter/webcoda.support.js");
            }

            //// Register Callback // ****** REMOVE CALLBACK **********
            //if (!pageScriptManager.IsClientScriptIncludeRegistered("WCTwitter_" + this.ClientID)) {
            //    StringBuilder scriptLoading = new StringBuilder();

            //    //CallServer will invoke RaiseCallbackEvent server-side out of band
            //    //ClientScriptManager pageScriptManager = this.Page.ClientScript;
            //    scriptLoading.AppendLine("function CallServer_" + this.ClientID + "(arg, context) {")
            //              .AppendLine("  try {")
            //              .AppendLine("   " + Page.ClientScript.GetCallbackEventReference(this, "arg", "HandleCallbackResult_" + this.ClientID , "context", true))
            //              .AppendLine("  } catch(e){window.status = 'ERROR:' + e.Message} ")
            //              .AppendLine("} ");

            //    //HandleCallbackResult will catch the string returned from server
            //    scriptLoading.AppendLine("function HandleCallbackResult_" + this.ClientID +"(arg, context) {")
            //              .AppendLine("  try {")
            //              .AppendLine("    document.getElementById(\"" + this.uiTxtMessage.ClientID + "\").value = \"\";")
            //              .AppendLine("    document.getElementById(\"" + this.uiBtnUpdate.ClientID + "\").value = \"UPDATE\";")
            //              .AppendLine("    document.getElementById(\"" + this.uiBtnUpdate.ClientID + "\").disabled = false;")
            //              .AppendLine("    var element = document.getElementById(context); ")
            //              .AppendLine("    if(element) {")
            //              .AppendLine("      element.innerHTML = arg; ")
            //              .AppendLine("    } ")
            //              .AppendLine("  } catch(e){window.status = 'ERROR:' + e.Message} ")
            //              .AppendLine("} ");
            //    pageScriptManager.RegisterStartupScript(this.GetType(), "WCTwitter_" + this.ClientID, scriptLoading.ToString(), true);
            //}

            //// Register Update click // ****** REMOVE CALLBACK **********
            //if (!pageScriptManager.IsClientScriptIncludeRegistered("WCTwitterSave_" + this.ClientID)) {
            //    StringBuilder scriptUpdating = new StringBuilder();
            //    scriptUpdating.AppendLine("function SaveMessage_" + this.ClientID + "(button) { ")
            //                  .AppendLine("   var message = document.getElementById(\"" + this.uiTxtMessage.ClientID + "\").value;")
            //                  .AppendLine("   if (message.length == 0) { alert(\"Please enter a message\"); return false ; } ")
            //                  .AppendLine("   var context = \"" + this.uiPnlDisplayContainer.ClientID +"\";")
            //                  .AppendLine("   button.value = \" ... \";")
            //                  .AppendLine("   button.disabled = true;")
            //                  .AppendLine("   CallServer_" + this.ClientID + "(message, context);")
            //                  .AppendLine("}");
            //    pageScriptManager.RegisterStartupScript(this.GetType(), "WCTwitterSave_" + this.ClientID, scriptUpdating.ToString(), true);
            //}


            // Register Style Sheet
            HtmlHead head = (HtmlHead)Page.Header;
            HtmlLink cssLink = new HtmlLink();
            cssLink.Attributes.Add("rel", "stylesheet");
            cssLink.Attributes.Add("type", "text/css");
            cssLink.Href = "/_layouts/webcoda.twitter/twitter.css";
            head.Controls.Add(cssLink);
        }

        /// <summary>
        /// Load the Controls
        /// </summary>
        private void LoadControls() {
            // Main Container
            this.uiPnlMainContainer.ID = "uiPnlMainContainer";
            this.uiPnlMainContainer.CssClass = "twittermain";

            // Text Box to the Page
            this.uiTxtMessage.ID = "uiTxtMessage";
            this.uiTxtMessage.MaxLength = this.MessageLimit;
            this.uiTxtMessage.Rows = 5;
            this.uiTxtMessage.TextMode = TextBoxMode.MultiLine;
            this.uiTxtMessage.CssClass = "twittertext";

            // Multi Line support - maxlength does not work on multiline
            this.uiTxtMessage.Attributes.Add("onkeypress", "doKeypress(event,this);");
            this.uiTxtMessage.Attributes.Add("onbeforepaste", "doBeforePaste(event,this);");
            this.uiTxtMessage.Attributes.Add("onpaste", "doPaste(event,this);");
            this.uiTxtMessage.Attributes.Add("maxLength", this.uiTxtMessage.MaxLength.ToString());

            // Update Button
            this.uiBtnUpdate.ID = "uiBtnUpdate";
            this.uiBtnUpdate.Text = "UPDATE";
            this.uiBtnUpdate.CssClass = "twitterupdate";
            this.uiBtnUpdate.Click += new EventHandler(uiBtnUpdate_Click);
            // this.uiBtnUpdate.OnClientClick = "javascript:SaveMessage_" + this.ClientID + "(this); return false;"; // ****** REMOVE CALLBACK **********

            // Update Container
            this.uiPnlUpdateContainer.ID = "uiPnlUpdateContainer";
            this.uiPnlUpdateContainer.CssClass = "twitterupdatecontainer";
            this.uiPnlUpdateContainer.Controls.Add(uiBtnUpdate);

            // Display Container
            this.uiRptDisplay.ID = "uiRptDisplay";
            this.uiPnlDisplayContainer.ID = "uiPnlDisplayContainer";
            this.uiPnlDisplayContainer.CssClass = "twitterupdatedisplay";
            this.uiPnlDisplayContainer.Controls.Add(uiRptDisplay);

            // More Link
            this.uiHypLnkMore.ID = "uiHypLnkMore";
            this.uiPnlMoreContainer.ID = "uiPnlMoreContainer";
            this.uiPnlMoreContainer.CssClass = "twittermore";
            this.uiPnlMoreContainer.Controls.Add(uiHypLnkMore);

            // Add Controls to Main Panel
            this.uiPnlMainContainer.Controls.Add(uiTxtMessage);
            this.uiPnlMainContainer.Controls.Add(uiPnlUpdateContainer);
            this.uiPnlMainContainer.Controls.Add(uiPnlDisplayContainer);
            this.uiPnlMainContainer.Controls.Add(uiPnlMoreContainer);

            // Add Main Panel to page
            this.Controls.Add(uiPnlMainContainer);
        }


        /// <summary>
        /// Databind Controls
        /// </summary>
        private void DatabindControls() {
            // Get Main List
            if (this.GetMainList()) {
                // Set the CAML Query for the List
                SPQuery oQuery = new SPQuery();
                oQuery.RowLimit = Convert.ToUInt32(this._ListRowLimit);
                oQuery.Query = this.ListQuery;

                // Get a repeater datasource
                uiRptDisplay.EnableViewState = false;
                uiRptDisplay.DataSource = this._MainList.GetItems(oQuery);

                // Databind the Event
                uiRptDisplay.ItemDataBound += new RepeaterItemEventHandler(uiRptDisplay_ItemDataBound);

                // Add ItemTemplate to the Repeated
                uiRptDisplay.ItemTemplate = new RepeaterItemTemplate("");

                // Databind the Repeater
                uiRptDisplay.DataBind();

                // Set the more Link
                this.uiHypLnkMore.NavigateUrl = this._MainList.DefaultViewUrl;
                this.uiHypLnkMore.Text = "more ...";
                //this.uiHypLnkMore.Target = "_blank";
            }
        }

        /// <summary>
        /// Get main List
        /// </summary>
        private bool GetMainList() {
            try {                
                // Get the existing List
                this._MainList = this._WebContext.Lists[this.ListName];

                // Found and initialised the list
                return true;
            } catch (Exception ex) {
                // Could not find the list
                return false;
            }
        }

        /// <summary>
        /// Create main list
        /// </summary>
        private void CreateMainList() {
            // List Not Found then add list
            Guid newListGuid = this._WebContext.Lists.Add(this.ListName, "Twitter Webpart Custom List", SPListTemplateType.GenericList);
            this._MainList = this._WebContext.Lists[newListGuid];
            this._MainList.WriteSecurity = 2;
            this._MainList.ReadSecurity = 1;

            // build the Fields
            SPFieldText flUserName = (SPFieldText)this._MainList.Fields.CreateNewField(SPFieldType.Text.ToString(), "Twitter_Username");
            flUserName.Description = "Username";
            flUserName.Required = true;
            flUserName.MaxLength = 100;

            SPFieldMultiLineText flMessage = (SPFieldMultiLineText)this._MainList.Fields.CreateNewField(SPFieldType.Note.ToString(), "Twitter_Message");
            flMessage.Description = "Message";
            flMessage.Required = true;
            flMessage.NumberOfLines = 10;
            flMessage.RichText = true;

            // Add Fields
            this._MainList.Fields.Add(flUserName);
            this._MainList.Fields.Add(flMessage);
            this._MainList.Update();

            // Add the fields to the default view of the list
            // Must get the fields from the list - InternalName doesn't get refreshed on our instances above!
            SPView defaultView = this._MainList.DefaultView;
            defaultView.ViewFields.Add(this._MainList.Fields["Twitter_Username"]);
            defaultView.ViewFields.Add(this._MainList.Fields["Twitter_Message"]);
            defaultView.ViewFields.Add(this._MainList.Fields["Created"]);
            defaultView.Query = this.ListQuery;
            defaultView.Update();
        }

        /// <summary>
        /// Add List Item ro Manin list
        /// </summary>
        private void AddMessage(string message) {
            // Check the message 
            if (string.IsNullOrEmpty(message)) {
                return;
            }

            // Too long message
            if (message.Length > this.MessageLimit) {
                this._ErrorMessageLog.AppendLine(string.Format("Please limit message to {0} characters.", this.MessageLimit));
                return;
            }

            // Add message
            SPListItem newListItem = this._MainList.Items.Add();
            newListItem["Twitter_Username"] = SPContext.Current.Web.CurrentUser.Name; // System.Web.HttpContext.Current.Request.LogonUserIdentity.Name; //SPContext.Current.Web.CurrentUser.Name;//System.Web.HttpContext.Current.User.Identity.Name;//System.Environment.UserName;
            newListItem["Twitter_Message"] = message;
            newListItem["Title"] = "Tweet";
            newListItem.Update();

            // Check total items in the list
            for (int i = this._MainList.Items.Count; i > this._ListTotalItems; i--) {
                // Remove first items
                this._MainList.Items[0].Delete();
            }
        }

        /// <summary>
        /// Display Error Messages
        /// </summary>
        /// <param name="writer"></param>
        private void DisplayErrorMessage(HtmlTextWriter writer) {
            writer.Write("<span style=\"color:Red;\">Error loading webpart: " + this._ErrorMessageLog.Replace(System.Environment.NewLine, "<br />").ToString() + "</span>");
        }

        /// <summary>
        /// Check to see if the exact same message has been entered
        /// by the same user so as to prevent duplicate messages caused
        /// by the user refreshing the page.
        /// </summary>
        /// <param name="messageText"></param>
        /// <returns></returns>
        private bool EntryIsDuplicate(string messageText) {
            SPQuery dupsQuery = new SPQuery();
            StringBuilder sb = new StringBuilder();

            sb.Append(string.Format(@"
                <Where>
                    <And>
                        <Eq>
                            <FieldRef Name='Twitter_Message' />
                            <Value Type='Note'>{0}</Value>
                        </Eq>
                        <Eq>
                            <FieldRef Name='Twitter_Username' />
                            <Value Type='Text'>{1}</Value>
                        </Eq>
                    </And>
                </Where>", messageText, SPContext.Current.Web.CurrentUser.Name));

            dupsQuery.Query = sb.ToString();

            if(this._MainList.GetItems(dupsQuery).Count > 0){
                return true;
            }else{
                return false;
            }
        }

        #endregion

        #region Events
        /// <summary>
        /// Repeater datbind event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiRptDisplay_ItemDataBound(Object sender, RepeaterItemEventArgs e) {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
                //DataRowView dataRow = e.Item.DataItem as DataRowView;
                SPListItem listItem = e.Item.DataItem as SPListItem;

                // Add the Text to  Literal
                Literal ItemTemplateContent = e.Item.FindControl("ItemTemplateContent") as Literal;

                ItemTemplateContent.Text = string.Format("<p class=\"twitteritem\"><span class=\"twitteritemname\">{0}</span> <span class=\"twitteritemmessage\">{1}</span></p>", listItem["Twitter_Username"].ToString(), listItem["Twitter_Message"].ToString());
            }

        }

        /// <summary>
        /// Create new Messages 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiBtnUpdate_Click(Object sender, EventArgs e) {
            try {
                //Executes the method with Full Control rights even if the user does not otherwise have Full Control 
                SPSecurity.RunWithElevatedPrivileges(delegate() {
                    SPSite site = new SPSite(SPContext.Current.Web.Url);
                    this._WebContext = site.OpenWeb();

                    // Allow GET request or without requiring a security validation
                    this._WebContext.AllowUnsafeUpdates = true;

                    // Create Main List if not found
                    if (!this.GetMainList()) {
                        this.CreateMainList();
                    }

                    if (!EntryIsDuplicate(this.uiTxtMessage.Text)) {
                        // Save the Message
                        this.AddMessage(this.uiTxtMessage.Text);
                    }

                    // Databind the Controls
                    this.DatabindControls();

                    // Clear Message
                    this.uiTxtMessage.Text = string.Empty;

                    //Cleanup
                    this._WebContext.Dispose();
                    site.Dispose();
                });
            } catch (Exception ex) {
                this._ErrorMessageLog.AppendLine(ex.Message);
            }
        }

        #endregion

        #region Classes
        /// <summary>
        /// Repeater Template Class
        /// </summary>
        private class RepeaterItemTemplate : ITemplate {
            string _InitialValue = string.Empty;

            public RepeaterItemTemplate(string initValue) {
                this._InitialValue = initValue;
            }

            public void InstantiateIn(Control container) {
                // Put a literal on the page
                Literal itemTemplateContent = new Literal();
                itemTemplateContent.ID = "ItemTemplateContent";
                itemTemplateContent.Text = this._InitialValue;
                container.Controls.Add(itemTemplateContent);
            }
        }
        #endregion Classes
    }
}